'''
Created on May 23, 2010

@author: roni
'''
#import sys
#sys.path.append('/usr/lib/python-support/python-glpk/python2.6')
#import glpk            # Import the GLPK module
from cvxopt import matrix
from cvxopt import solvers
from ns2Scenario import Ns2Scenario
from projectConstants import ProjectConstants


class LinearProgrammingDiagnoser(object):
    ACCURACY_BUFFER = 0.0001
    def __init__(self):
        print "Testing"
        
    def run(self):
        # Matrix of x1+x2+x3+..+xn coefficients
        variables_matrix = matrix([ [-1.0, -1.0, 0.0, 1.0], [1.0, -1.0, -1.0, -2.0] ])
        results_vector = matrix([ 1.0, -2.0, 0.0, 4.0 ])
        target_function = matrix([ 2.0, 1.0 ]) # minimize 2x1+x2
        solution=solvers.lp(target_function,variables_matrix,results_vector)
        
        
        print solution['x']
    
    def run_on_scenario(self,original_scenario, flow_to_details):
        ''' Run LP diagnosis on given scenario and observerd flow to details '''
        equations = []        
        results_vector = []    
        for agent in original_scenario.agents:
            equation0 = [0.0 for i in xrange(original_scenario.num_of_nodes)]
            equation1 = [0.0 for i in xrange(original_scenario.num_of_nodes)]
            observed_delay=flow_to_details[agent].delay
            expected_delay=original_scenario.expected_delay[agent]
            for node in original_scenario.agent_to_path[agent][1:-1]:              
                equation0[node]=2.0
                equation1[node]=-2.0
            unexplained=observed_delay-expected_delay
            # Divide by link steps to escape accuracy errors and insignficant queuing delays.
            #unexplained= round(unexplained/Ns2Scenario.LINK_DELAY)*Ns2Scenario.LINK_DELAY
            equations.append(equation0)
            results_vector.append(unexplained+LinearProgrammingDiagnoser.ACCURACY_BUFFER)
            equations.append(equation1)
            results_vector.append(-unexplained+LinearProgrammingDiagnoser.ACCURACY_BUFFER)
            
        # Add constraint to enforce no negative unexpected delays
        for node in original_scenario.nodes:
            equation = [0.0 for i in xrange(original_scenario.num_of_nodes)]
            equation[node]=-1.0
            equations.append(equation)
            results_vector.append(0)
        
        # Add target function
        equation = [1.0 for i in xrange(original_scenario.num_of_nodes)]
        target_function = matrix(equation) # minimize 2x1+x2
        variables_matrix = matrix(equations)
        variables_matrix = variables_matrix.trans()
        results_matrix = matrix(results_vector)

#        # PRint equations for debug
        debug_file = file("%s/debug.txt" % ProjectConstants.RESROUCE_DIR,'w')
        debug_file.write("Matrix\n")
        for line in equations:
            debug_file.write("%s\n" % line)
        debug_file.write("Results\n")
        debug_file.write("%s\n" % results_vector)
        debug_file.write("Target function\n")
        debug_file.write("%s\n" % equation)
        debug_file.close()
        #      
        solution=solvers.lp(target_function,variables_matrix,results_matrix)
        node_to_delay = dict()
        solution = solution['x']
        for node in xrange(len(solution)):
            delay = solution[node]
            if abs(delay-0)>LinearProgrammingDiagnoser.ACCURACY_BUFFER:
                node_to_delay[node] = delay*1000
        return node_to_delay
   